#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "http_status.h"
#include "authn.h"
#include "base64.h"


/* user credentials struct */
typedef struct user_credentials_struct {
    const char           *username;
    const char           *password;
} user_credentials_rec;

static void note_auth_failure(request_rec *r);
static int get_user_credentials_rec(request_rec *r, user_credentials_rec *creds);
static void get_server_creds(request_rec *r, user_credentials_rec *server_creds);

int authenticate_basic_user(request_rec *r) {
	user_credentials_rec *creds = (user_credentials_rec*) malloc(sizeof(*creds));

    if (get_user_credentials_rec(r, creds) == HTTP_UNAUTHORIZED) {
		note_auth_failure(r);

		return HTTP_UNAUTHORIZED;
    }

    user_credentials_rec *server_creds = (user_credentials_rec*) malloc(sizeof(*server_creds));

    get_server_creds(r, server_creds);

    if ((strcmp(server_creds->password, creds->password) == 0) && (strcmp(server_creds->username, creds->username) == 0)) {
    	return OK;
    }
    else {
		note_auth_failure(r);

		return HTTP_UNAUTHORIZED;
	}
}

static int get_user_credentials_rec(request_rec *r, user_credentials_rec *creds) {
    char* request = r->buffer;
    char* delim = "**";
    char* token = strtok(request, "**");
    char* basic_header = "Authorization: Basic ";
    char* space = " ";
    char* colon = ":";

    while(token != NULL) {

    	//Look for the auth header
		if(strstr(token, basic_header)) {
			token = strtok(token, space);

			strtok(NULL, space);

			//we now have the base64 encoded string with the username and password
			token = strtok(NULL, space);

			unsigned char* temp_decoded_string = (char*)malloc(256);

			base64_decode(token, temp_decoded_string, BUFSIZE);

			creds->username = strtok(temp_decoded_string, colon);
			creds->password = strtok(NULL, colon);
			token = NULL;
		}

		token = strtok(NULL, delim);
    }

    if (!creds->username || !creds->password) {
        return HTTP_UNAUTHORIZED;
    }
    else {
    	return OK;
    }
}

static void note_auth_failure(request_rec *r) {
    // Hard code server response
    char* realm		= "Basic Auth - Secure Area";

    (void) sprintf(r->buffer, "HTTP/1.0 401 Authorization Required\r\nWWW-Authenticate: Basic realm=\"%s\"\r\n\r\n",
	    realm);
    (void) write(r->fd, r->buffer, strlen(r->buffer));
    (void) sprintf(r->buffer, "<html><head><title>Auth Error</title></head><body><h1>401 Unauthorized.</h1></body></html>\r\n\r\n");
    (void) write(r->fd, r->buffer, strlen(r->buffer));
}

static void get_server_creds(request_rec *r, user_credentials_rec *server_creds) {
    char *user = malloc(256);
    char *password = malloc(256);

    // Read local password file
    auth_config *config = get_auth_config(r);

    FILE *ifp = fopen(config->auth_user_file, "r");

    if (ifp) {
    	fscanf(ifp, "%256[^:\n]:%256[^:\n]", user, password);

    	server_creds->password = password;
    	server_creds->username = user;
    }
}
